package de.lmu.ifi.pst.uwejsf.framework;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

public class UWEHelpers {
	public static String firstToLower(String str) {
		if (str == null)
			return null;
		if (str.length() == 0)
			return "";
		if (str.length() == 1)
			return str.toLowerCase();
		return str.substring(0, 1).toLowerCase().concat(str.substring(1));
	}

	public static String firstToUpper(String str) {
		if (str == null)
			return null;
		if (str.length() == 0)
			return "";
		if (str.length() == 1)
			return str.toUpperCase();
		return str.substring(0, 1).toUpperCase().concat(str.substring(1));
	}

	public static <T> List<T> convertListContent(Object rawContent,
			Class<T> expectedElementClass) {
		if (rawContent == null)
			return null;

		if (!(rawContent instanceof Collection<?>))
			return null;

		List<T> result = new ArrayList<T>();

		Collection<?> sourceCollection = (Collection<?>) rawContent;

		for (Object element : sourceCollection) {
			T castedElement = convertSingleContent(element,
					expectedElementClass);

			if (castedElement != null)
				result.add(castedElement);
		}

		return result;
	}

	public static <T> T convertSingleContent(Object rawContent,
			Class<T> expectedClass) {
		if (rawContent == null)
			return null;
		T result = null;

		if (ItemWrapper.class.isInstance(rawContent)) {
			ItemWrapper itemWrapper = ItemWrapper.class.cast(rawContent);
			Object rawWrappedItem = itemWrapper.getWrappedItem();
			if (expectedClass.isInstance(rawWrappedItem))
				result = expectedClass.cast(rawWrappedItem);
		} else if (rawContent instanceof List<?>) {
			List<?> rawList = (List<?>) rawContent;
			if (rawList.size() > 0)
				result = convertSingleContent(rawList.get(0), expectedClass);
		} else {
			// expected class could be object, so do this as last step
			if (expectedClass.isAssignableFrom(rawContent.getClass()))
				result = expectedClass.cast(rawContent);

		}
		return result;
	}

	public static boolean isReadableProperty(Object bean, String property) {

		return PropertyUtils.isReadable(bean, property);
	}

	public static boolean isWritableProperty(Object bean, String property) {

		return PropertyUtils.isWriteable(bean, property);
	}

	public static Object getProperty(Object bean, String property) {
		Object result = null;
		try {
			result = PropertyUtils.getProperty(bean, property);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return result;
	}

	public static void copyProperties(Object dest, Object source) {
		try {
			BeanUtils.copyProperties(dest, source);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static Map<String, Object> getSelectedBeanProperties(Object bean,
			Set<String> excludes) throws IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {

		Map<String, Object> result = new HashMap<String, Object>();
		PropertyDescriptor[] propertyDescriptors = PropertyUtils
				.getPropertyDescriptors(bean);
		for (PropertyDescriptor pd : propertyDescriptors) {

			if (pd.getReadMethod() != null && !excludes.contains(pd.getName())) {

				result.put(pd.getName(), PropertyUtils.getProperty(bean, pd
						.getName()));
			}
		}
		return result;

	}

	public static Object getDefaultValueForType(Class<?> pt) {
		Object value = null;
		if (List.class.isAssignableFrom(pt))
			value = new LinkedList<Object>();
		else if (Set.class.isAssignableFrom(pt))
			value = new HashSet<Object>();
		else if (Map.class.isAssignableFrom(pt))
			value = new HashMap<Object, Object>();
		else if (pt.equals(int.class))
			value = 0;
		else if (pt.equals(long.class))
			value = 0L;
		else if (pt.equals(boolean.class))
			value = false;
		else if (pt.equals(float.class))
			value = 0f;
		else if (pt.equals(double.class))
			value = 0.0;
		else if (pt.equals(byte.class))
			value = (byte) 0;
		else if (pt.equals(char.class))
			value = (char) 0;
		return value;
	}
}
